跳到主要内容
版本:Next

RESTful API 集成

目录

  1. 简介
  2. 项目结构概览
  3. 核心请求封装模块
  4. API 接口组织架构
  5. 认证与安全机制
  6. 环境配置与代理
  7. 错误处理与统一响应
  8. 缓存策略与性能优化
  9. 分页与参数处理
  10. Mock 数据与开发调试
  11. 实际使用示例
  12. 最佳实践与扩展指南

简介

lmes-web-base 项目采用基于 axios 的 RESTful API 集成方案,提供了完整的前后端通信解决方案。该系统通过精心设计的请求封装层、统一的错误处理机制、智能的缓存策略以及灵活的环境配置,为前端应用提供了稳定可靠的 API 通信能力。

项目结构概览

图表来源

核心请求封装模块

request.ts 模块架构

request.ts 是整个 API 集成的核心模块,基于 axios 进行了深度封装,提供了完整的请求生命周期管理。

图表来源

请求拦截器功能

请求拦截器负责在请求发送前进行预处理:

  1. 认证令牌注入:自动从 Session 存储中获取 Token 并添加到 Authorization 头
  2. 默认请求头设置:合并默认的 Content-Type 和其他业务相关头部
  3. XML 字符串处理:识别并正确处理 XML 格式的字符串数据
  4. 静默模式支持:根据配置决定是否显示加载动画

响应拦截器功能

响应拦截器处理服务器返回的数据:

  1. 数据提取:自动提取 response.data 部分
  2. 错误代理检测:识别并处理代理未找到的接口
  3. Blob 类型处理:特殊处理文件下载场景
  4. 状态码映射:将 HTTP 状态码映射为用户友好的错误消息

章节来源

API 接口组织架构

项目级 API 组织

项目采用模块化的 API 组织方式,每个业务领域都有独立的 API 文件:

图表来源

API 方法类型支持

系统支持完整的 RESTful 方法:

  • GET:用于数据查询和资源获取
  • POST:用于数据创建和复杂查询
  • PUT:用于资源更新
  • DELETE:用于资源删除

章节来源

认证与安全机制

Token 注入机制

系统实现了自动化的 Token 管理机制:

// 自动从 Session 存储获取 Token
const token = Session.get('Token')

// 动态计算 Authorization 头
get Authorization() {
return token ? `Bearer ${token}` : undefined
}

请求头安全策略

  1. Content-Type 强制:确保所有请求都使用 application/json 格式
  2. 项目标识:自动注入 X-Project 头部标识当前项目
  3. 客户端标识:添加 X-Client-Id 支持多客户端识别
  4. 语言环境:动态设置 Accept-Language 头部

重新登录机制

当遇到 401 或 403 状态码时,系统会触发重新登录弹窗:

图表来源

章节来源

环境配置与代理

环境变量驱动的 baseURL 切换

系统支持通过多种方式配置 baseURL:

// 优先从 URL 参数获取
let baseURL = params.get('baseURL') || ''

// 支持通过 baseURL 参数覆盖
console.info('[baseURL]', baseURL)

开发环境代理配置

开发环境通过 Vite 配置了完整的代理系统:

图表来源

路径别名配置

系统配置了多个路径别名以简化导入:

  • @./src
  • components./src/components
  • sdk./src/cms/sdk.es.js

章节来源

错误处理与统一响应

统一错误处理机制

系统实现了多层次的错误处理:

图表来源

错误消息处理

系统支持多种错误消息来源:

  1. 响应体错误:优先从 data.msgdata.message 等字段获取
  2. 状态文本:使用 statusText 作为备选
  3. 默认消息:使用 "请求出错" 作为最终备选

加载动画管理

系统实现了智能的加载动画管理:

// 请求计数器
let reqNum: number = 0

// 显示加载动画
const setLoading = (silent: boolean) => {
if (silent) return

reqNum++
if (reqNum === 1) {
loadingInstance = ElLoading.service(loadingOptions)
}
}

// 关闭加载动画
const closeLoading = (silent: boolean) => {
if (silent) return
reqNum--
if (reqNum <= 0) {
reqNum = 0
loadingInstance && loadingInstance.close()
}
}

章节来源

缓存策略与性能优化

内存缓存机制

系统实现了基于内存的缓存策略:

图表来源

变量查询缓存

系统对变量查询实现了 5 分钟缓存机制:

private async queryVariable(next: () => void) {
const size = this.getState(Base.MAP_KEY)?.size
const t = this.getState(Base.CACHE_KEY) || Date.now()

// 缓存有效期内直接返回
if (size > 0 && Date.now() - t < Base.CACHE_TIME) {
return next && next()
}

// 缓存过期,发起新请求
try {
const vars = await request.get('/api/v1/variable/query')
const varMap = this.transformArrayToMap(vars.result)
this.setState(Base.CACHE_KEY, Date.now())
this.setState(Base.MAP_KEY, varMap)
next && next()
} catch (error) {
console.error(error, '变量查询接口报错,暂停请求')
}
}

节流防抖机制

系统提供了高性能的节流防抖工具:

export const genSetInterval = (fn: () => void, time: number = 33): Timer => {
let timerId: number | null = null
let lastTime = performance.now()

const loop = (currentTime: number) => {
const deltaTime = currentTime - lastTime

if (deltaTime >= time) {
fn()
lastTime = currentTime - (deltaTime % time) // 保留余下的时间,减少漂移
}

timerId = requestAnimationFrame(loop)
}

return {
start() {
if (timerId === null) {
lastTime = performance.now()
timerId = requestAnimationFrame(loop)
}
},
clear() {
if (timerId !== null) {
cancelAnimationFrame(timerId)
timerId = null
}
},
}
}

章节来源

分页与参数处理

分页参数标准化

系统实现了统一的分页参数处理机制:

图表来源

分页组件实现

系统提供了两个分页组件:

  1. BaseTable 分页:集成在表格组件中
  2. MyPages 组件:独立的分页控件
// 分页参数获取
const getPaginationParams = () => {
return {
pageNum: pageNum.value,
pageSize: params.value.MaxResultCount,
totalCount: totalCount.value,
}
}

// 表格滚动到指定行
const scrollToRow = async ({ row, skip }: any) => {
if (skip) {
if (totalCount.value > dataSource.value.length) {
// 跳转到最后一页面
pageNum.value = Math.ceil(totalCount.value / params.value.MaxResultCount)
params.value.SkipCount = (pageNum.value - 1) * params.value.MaxResultCount
}
await getTableList()
skipRow(dataSource.value[dataSource.value.length - 1])
} else {
skipRow(row)
}
}

参数序列化处理

系统自动处理各种类型的参数序列化:

// 自动 JSON 序列化
if (
typeof config.data !== 'object' &&
!isXMLString &&
config.headers['Content-Type'].match(/application\/json/i)
) {
config.data = JSON.stringify(config.data)
}

章节来源

Mock 数据与开发调试

Mock 系统架构

系统提供了完整的 Mock 数据支持:

图表来源

开发环境调试支持

系统支持多种开发调试模式:

  1. 静态文件 Mock:通过 mock.json 提供静态数据
  2. 动态 Mock:通过 index.js 提供动态行为
  3. 多语言 Mock:支持本地化测试
  4. 组件 Mock:支持组件级别的模拟

接口联调机制

开发环境提供了完整的接口联调支持:

// 开发环境与生产环境的 API 路由切换
return import.meta.env.PROD
? sdk.request({ url, method, params: { ...provider } })
: request({ url, method, params: { ...provider } })

章节来源

实际使用示例

基础 API 调用

// 项目配置获取
export const getProjectConfig = (name: string) => {
return request.get(`/projectApi/env?name=${name}`)
}

// 组件创建
export const createWidget = (data) => {
return request.post(`/projectApi/create`, data)
}

高级 API 调用

// 产品列表查询(带条件过滤)
function getproductList(data: any, hasFormula: boolean = true) {
const url = `api/v1/messuite/query/product?filter=${data.filter}&hasFormula=${hasFormula}`
const method = 'get'
return request({ url, method })
}

// 工序列表查询(带能力类型过滤)
function getWorksectionList(data: any) {
const url = `api/v1/messuite/query/worksection?filter=${data.filter}&abilityType=${data.abilityType}&includeDetails=${data.includeDetails}`
const method = 'get'
return request({ url, method })
}

错误处理示例

// 带静默模式的请求
try {
const result = await request.get('/api/v1/data', {
silent: true, // 不显示加载动画
unLogError: true, // 不显示错误提示
})
} catch (error) {
console.error('API 调用失败:', error)
}

文件上传示例

// 文件上传(支持 FormData)
export const postImport = (file: FormData) => {
return request({
url: `/api/v1/zc/productsop/uploadsop`,
method: 'post',
contentType: 'multipart/form-data',
headers: { accept: '*/*' },
data: file,
})
}

章节来源

最佳实践与扩展指南

扩展自定义请求头

// 在请求配置中添加自定义头部
const customRequest = async (url: string, data?: any) => {
return request({
url,
method: 'post',
headers: {
'X-Custom-Header': 'custom-value',
'X-Additional-Info': 'additional-info',
},
data,
})
}

适配分页参数格式

// 统一分页参数处理
const getPagedParams = (pageNum: number, pageSize: number) => {
return {
SkipCount: (pageNum - 1) * pageSize,
MaxResultCount: pageSize,
}
}

// 使用示例
const fetchData = async (pageNum: number, pageSize: number) => {
const params = getPagedParams(pageNum, pageSize)
return request.get('/api/v1/data/list', { params })
}

接口版本控制

// 版本化 API 调用
const apiVersion = 'v1'

const getVersionedRequest = (endpoint: string) => {
return request.get(`/api/${apiVersion}/${endpoint}`)
}

// 使用示例
const getData = async () => {
return getVersionedRequest('data')
}

高频请求节流

// 节流包装器
const createThrottledRequest = (fn: Function, delay: number = 300) => {
let lastCall = 0
return async (...args: any[]) => {
const now = Date.now()
if (now - lastCall < delay) {
return Promise.reject(new Error('请求过于频繁'))
}
lastCall = now
return fn(...args)
}
}

// 使用示例
const throttledGetData = createThrottledRequest(getData)

扩展错误处理

// 自定义错误处理器
const handleError = (error: any) => {
switch (error.status) {
case 400:
ElMessage.error('请求参数错误')
break
case 401:
ElMessage.error('请先登录')
break
case 403:
ElMessage.error('权限不足')
break
case 404:
ElMessage.error('资源不存在')
break
default:
ElMessage.error('网络错误,请稍后重试')
}
}

性能监控集成

// 请求性能监控
const monitoredRequest = async (config: any) => {
const startTime = performance.now()
try {
const result = await request(config)
const endTime = performance.now()
console.log(`API ${config.url} 耗时: ${endTime - startTime}ms`)
return result
} catch (error) {
const endTime = performance.now()
console.error(`API ${config.url} 失败,耗时: ${endTime - startTime}ms`)
throw error
}
}

这个文档全面涵盖了 lmes-web-base 项目中 RESTful API 集成的所有关键方面,从基础的请求封装到高级的性能优化,为开发者提供了完整的技术参考和最佳实践指导。通过合理的架构设计和丰富的功能特性,该系统能够满足现代 Web 应用对 API 集成的各种需求。